﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MonoTorrent.Client;
using TorrentService;
using log4net;
using System.IO;
using MonoTorrent.Client.Encryption;
using System.Threading;
using MonoTorrent.Common;
using XmlSettings;

namespace BotTorrent
{
    public class BitTorrentClient
    {
        // Fields
        private string basePath = Environment.CurrentDirectory;
        private string dhtNodeFile;
        private ClientEngine engine;
        public EngineSettings engineSettings;
        private ircbot IrcBot;
        private static readonly ILog log = LogManager.GetLogger(typeof(BotTorrent));
        private List<TorrentManager> massPaused = new List<TorrentManager>();
        public XmlSettings.Settings Settings;
        public MonoTorrent.Client.TorrentSettings torrentDefaults;
        public List<TorrentManager> TorrentList;

        // Methods
        public BitTorrentClient(Settings conf, ircbot oIrcBot)
        {
            this.dhtNodeFile = Path.Combine(this.basePath, "DhtNodes");
            this.Settings = conf;
            this.IrcBot = oIrcBot;
            this.TorrentList = new List<TorrentManager>();
            AppDomain.CurrentDomain.ProcessExit += delegate
            {
                this.shutdown();
            };
            AppDomain.CurrentDomain.UnhandledException += delegate(object sender, UnhandledExceptionEventArgs e)
            {
                Console.WriteLine(e);
                this.shutdown();
            };
            Thread.GetDomain().UnhandledException += delegate(object sender, UnhandledExceptionEventArgs e)
            {
                Console.WriteLine(e);
                this.shutdown();
            };
            this.engineSettings = new EngineSettings(this.Settings.TorrentSettings.downloadsPath, this.Settings.TorrentSettings.listenPort, this.Settings.TorrentSettings.MaxConnections, this.Settings.TorrentSettings.MaxHalfOpenConnections, this.Settings.TorrentSettings.MaxDownloadSpeed, this.Settings.TorrentSettings.MaxUploadSpeed, EncryptionTypes.All);
            this.engineSettings.PreferEncryption = true;
            this.engineSettings.AllowedEncryption = EncryptionTypes.All;
            this.torrentDefaults = new MonoTorrent.Client.TorrentSettings(this.Settings.TorrentSettings.defaultUploadSlots, this.Settings.TorrentSettings.defaultMaxConn, this.Settings.TorrentSettings.defaultDownloadRate, this.Settings.TorrentSettings.defaultUploadRate, false);
            this.engine = new ClientEngine(this.engineSettings);
            //this.engine.ChangeListenEndpoint(new System.Net.IPEndPoint(System.Net.IPAddress.Any, 5002));
            byte[] nodes = null;
            try
            {
                nodes = File.ReadAllBytes(this.dhtNodeFile);
            }
            catch
            {
                log.Debug("No existing dht nodes could be loaded");
            }
            this.StartEngine();
        }

        public TorrentManager GetTorrentManager(string torrentInfoHash)
        {
            return this.TorrentList.Find(delegate(TorrentManager e)
            {
                return Toolbox.ToHex(e.Torrent.InfoHash) == torrentInfoHash;
            });
        }

        protected void OnContinue()
        {
            foreach (TorrentManager torrent in this.massPaused)
            {
                torrent.Start();
            }
        }

        protected void OnPause()
        {
            this.massPaused.Clear();
            foreach (TorrentManager torrent in this.TorrentList)
            {
                if ((torrent.State == TorrentState.Downloading) || (torrent.State == TorrentState.Seeding))
                {
                    this.massPaused.Add(torrent);
                }
            }
            this.engine.PauseAll();
        }

        protected void OnStop()
        {
            this.StopAllTorrents();
            this.engine.Listener.Stop();
            this.engine.DhtEngine.Stop();
        }

        public bool PauseTorrent(string torrentInfoHash)
        {
            TorrentManager torrent = this.GetTorrentManager(torrentInfoHash);
            torrent.Pause();
            log.Info(string.Format("Torrent \"{0}\" paused.", torrent.Torrent.Name));
            return true;
        }

        internal void Register(TorrentManager manager)
        {
            this.engine.Register(manager);
        }

        public bool RemoveTorrent(string torrentInfoHash, bool removeData)
        {
            TorrentManager torrent = this.GetTorrentManager(torrentInfoHash);
            torrent.Stop().WaitOne();
            this.engine.Unregister(torrent);
            this.TorrentList.Remove(torrent);
            log.Info(string.Format("Torrent \"{0}\" removed.", torrent.Torrent.Name));
            return true;
        }

        public void shutdown()
        {
            Thread.Sleep(0x7d0);
        }

        public void StartAll()
        {
            this.engine.StartAll();
        }

        public void StartEngine()
        {
            Exception e;
            log.Info("Starting BitTorrent Engine");
            if (!Directory.Exists(this.engine.Settings.SavePath))
            {
                try
                {
                    Directory.CreateDirectory(this.engine.Settings.SavePath);
                    log.Info("Sucessfully created directory " + this.engine.Settings.SavePath);
                }
                catch (Exception exception1)
                {
                    e = exception1;
                    log.Error("Unable to create savepath + " + this.engine.Settings.SavePath + " " + e.Message);
                }
            }
            if (!Directory.Exists(this.Settings.TorrentSettings.torrentsPath))
            {
                try
                {
                    Directory.CreateDirectory(this.Settings.TorrentSettings.torrentsPath);
                    log.Info("Sucessfully created directory " + this.Settings.TorrentSettings.torrentsPath);
                }
                catch (Exception exception2)
                {
                    e = exception2;
                    log.Error("Unable to create Settings.torrentsPath + " + this.Settings.TorrentSettings.torrentsPath + " " + e.Message);
                }
            }
            if (this.Settings.TorrentSettings.ResumeOnAppStart)
            {
                log.Info("ResumeOnAppStart enabled, loading any preexisting torrents in " + this.Settings.TorrentSettings.torrentsPath);
                foreach (string file in Directory.GetFiles(this.Settings.TorrentSettings.torrentsPath))
                {
                    if (file.EndsWith(".torrent") && (this.TorrentList.Count != this.Settings.TorrentSettings.MaxDownloads))
                    {
                        try
                        {
                            TorrentManager manager = new TorrentManager(Torrent.Load(file), this.Settings.TorrentSettings.downloadsPath, this.torrentDefaults, this.Settings.TorrentSettings.downloadsPath, null);
                            this.engine.Register(manager);
                            this.TorrentList.Add(manager);
                            log.Debug("Successfully added torrent " + file);
                        }
                        catch (Exception exception3)
                        {
                            e = exception3;
                            log.Error("Unable to add torrent " + file + " " + e.Message);
                        }
                    }
                }
            }
            foreach (TorrentManager manager in this.TorrentList)
            {
                manager.HashCheck(true);
                manager.Start();
                log.Info("Successfully started torrent " + manager.Torrent.Name);
            }
        }

        public bool StartTorrent(string torrentInfoHash)
        {
            TorrentManager torrent = this.GetTorrentManager(torrentInfoHash);
            torrent.Start();
            log.Info(string.Format("Torrent \"{0}\" started.", torrent.Torrent.Name));
            return true;
        }

        private void StopAllTorrents()
        {
            this.engine.StopAll();
        }

        public bool StopTorrent(string torrentInfoHash)
        {
            TorrentManager torrent = this.GetTorrentManager(torrentInfoHash);
            torrent.Stop().WaitOne();
            log.Info(string.Format("Torrent \"{0}\" stopped.", torrent.Torrent.Name));
            return true;
        }

        internal void Unregister(TorrentManager torrentManager)
        {
            this.engine.Unregister(torrentManager);
        }
    }
}
